package com.andova.empty.widget;

import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.andova.empty.api.IEmptyActivityOption;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

class EmptyViewGroupAgent {
    private IEmptyActivityOption mAppOptions;
    private IEmptyActivityOption mActivityOptions;

    private View mEmptyView;
    private View mErrorView;
    private View mLoadingView;

    private int mState = State.CONTENT;

    private final String TAG = EmptyViewGroupAgent.class.getSimpleName();

    EmptyViewGroupAgent(@NonNull IEmptyActivityOption option) {
        mAppOptions = option;
    }

    /**
     * @see ViewGroup#onFinishInflate()
     */
    void onFinishInflate(ViewGroup parent) {
        mState = State.EMPTY;
        try {
            View.inflate(parent.getContext(), mActivityOptions != null
                    ? mActivityOptions.emptyStateLayout()
                    : mAppOptions.emptyStateLayout(), parent);
        } catch (Resources.NotFoundException e) {
            Log.w(TAG, "there is no empty state layout resource.");
        }
        mState = State.ERROR;
        try {
            View.inflate(parent.getContext(), mActivityOptions != null
                    ? mActivityOptions.errorStateLayout()
                    : mAppOptions.errorStateLayout(), parent);
        } catch (Resources.NotFoundException e) {
            Log.w(TAG, "there is no error state layout resource.");
        }
        mState = State.LOADING;
        try {
            View.inflate(parent.getContext(), mActivityOptions != null
                    ? mActivityOptions.loadingStateLayout()
                    : mAppOptions.loadingStateLayout(), parent);
        } catch (Resources.NotFoundException e) {
            Log.w(TAG, "there is no loading state layout resource.");
        }
        mState = State.CONTENT;
    }

    /**
     * @see ViewGroup#addView(View, int, ViewGroup.LayoutParams)
     */
    void addView(View child) {
        switch (mState) {
            case State.EMPTY:
                mEmptyView = child;
                mEmptyView.setVisibility(GONE);
                break;
            case State.ERROR:
                mErrorView = child;
                mErrorView.setVisibility(GONE);
                break;
            case State.LOADING:
                mLoadingView = child;
                mLoadingView.setVisibility(GONE);
                break;
        }
    }

    void showLoading(ViewGroup parent) {
        setState(parent, State.LOADING);
    }

    void showError(ViewGroup parent) {
        setState(parent, State.ERROR);
    }

    void showEmpty(ViewGroup parent) {
        setState(parent, State.EMPTY);
    }

    void showContent(ViewGroup parent) {
        setState(parent, State.CONTENT);
    }

    void setEmptyOption(IEmptyActivityOption options) {
        mActivityOptions = options;
    }

    private void setState(ViewGroup parent, @State int state) {
        switch (state) {
            case State.LOADING:
                setupLoadingView();
                setContentVisibility(parent, GONE);
                break;
            case State.EMPTY:
                setupEmptyView();
                setContentVisibility(parent, GONE);
                break;
            case State.ERROR:
                setupErrorView();
                setContentVisibility(parent, GONE);
                break;
            case State.CONTENT:
                if (getEmptyView() != null) getEmptyView().setVisibility(GONE);
                if (getErrorView() != null) getErrorView().setVisibility(GONE);
                if (getLoadingView() != null) getLoadingView().setVisibility(GONE);
                setContentVisibility(parent, VISIBLE);
                break;
        }
    }

    private void setContentVisibility(ViewGroup parent, int visibility) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            if (getEmptyView() != null && child == getEmptyView()) continue;
            if (getErrorView() != null && child == getErrorView()) continue;
            if (getLoadingView() != null && child == getLoadingView()) continue;
            if (filter(child)) continue;
            child.setVisibility(visibility);
        }
    }

    private boolean filter(View child) {
        if (child instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) child).getChildCount(); i++) {
                if (filter(((ViewGroup) child).getChildAt(i))) return true;
            }
        }
        IEmptyActivityOption option = mActivityOptions != null ? mActivityOptions : mAppOptions;
        if (option.filterViewClassName() != null
                && (option.filterViewClassName().contains(child.getClass().getName())
                || option.filterViewClassName().contains(child.getClass().getSimpleName()))) {
            return true;
        } else if (option.filterViewId() != null
                && option.filterViewId().contains(child.getId())) {
            return true;
        }
        return false;
    }

    private void setupLoadingView() {
        if (getLoadingView() == null) return;
        getLoadingView().setVisibility(VISIBLE);
        if (getEmptyView() != null) getEmptyView().setVisibility(GONE);
        if (getErrorView() != null) getErrorView().setVisibility(GONE);
    }

    private void setupEmptyView() {
        if (getEmptyView() == null) return;
        getEmptyView().setVisibility(VISIBLE);
        if (getLoadingView() != null) getLoadingView().setVisibility(GONE);
        if (getErrorView() != null) getErrorView().setVisibility(GONE);
    }

    private void setupErrorView() {
        if (getErrorView() == null) return;
        getErrorView().setVisibility(VISIBLE);
        if (getLoadingView() != null) getLoadingView().setVisibility(GONE);
        if (getEmptyView() != null) getEmptyView().setVisibility(GONE);
    }

    View getEmptyView() {
        return mEmptyView;
    }

    View getErrorView() {
        return mErrorView;
    }

    View getLoadingView() {
        return mLoadingView;
    }

    IEmptyActivityOption getOptions() {
        return mActivityOptions == null ? mAppOptions : mActivityOptions;
    }

    @IntDef({State.CONTENT, State.EMPTY, State.ERROR, State.LOADING})
    @Retention(RetentionPolicy.SOURCE)
    @interface State {
        int LOADING = 0;
        int EMPTY = 1;
        int ERROR = 2;
        int CONTENT = 3;
    }
}